manyhow
anyhow for proc macros
Proc macro anyhow, a combination of ideas from
anyhow
and
proc-macro-error
to improve proc macro
development, especially focused on the error handling.
Motivation
Error handling in proc-macros is unideal, as the top level functions of proc
macros can only return TokenStreams
both in success and failure case. This
means that I often write code like this, moving the actual implementation in
a separate function to be able to use the ergonomic rust error handling with
e.g., ?
.
use TokenStream as TokenStream2;
Using the #[manyhow]
macro
To activate the error handling, just add #[manyhow]
above any
proc macro implementation, reducing the above example to:
use manyhow;
use TokenStream as TokenStream2;
See Without macros to see what this expands to under the hood.
A proc macro function marked as #[manyhow]
can take and return any
TokenStream
and can also return Result<TokenStream, E>
where E
implements ToTokensError
. As additional parameters a
dummy and/or emitter can
be specified.
The manyhow
attribute takes one optional flag when used for proc_macro
and proc_macro_attribute
. #[manyhow(input_as_dummy)]
will take the input
of a function like proc_macro
to initialize the dummy &mut TokenStream
while #[manyhow(item_as_dummy)]
on
proc_macro_attribute
will initialize the dummy with the annotated item.
Without macros
manyhow
can be used without proc macros, and they can be disabled by
adding manyhow
with default-features=false
.
The usage is more or less the same, though with some added boilerplate from
needing to invoke one of function
, attribute
or derive
directly.
While the examples use closures, functions can be passed in as well. The above example would then change to:
use TokenStream as TokenStream2;
Emitter
and dummy
TokenStream
can also be used. function
and
attribute
take an additional boolean parameter controlling whether the
input/item will be used as initial dummy.
emitter: &mut Emitter
MacroHandler
s (the trait defining what closures/functions can be used
with manyhow
) can take a mutable reference to an Emitter
. This
allows to collect errors, but not fail immediately.
Emitter::into_result
can be used to return if an Emitter
contains
any values.
use ;
use TokenStream as TokenStream2;
dummy: &mut TokenStream
MacroHandler
s also take a mutable reference to a TokenStream
, to
enable emitting some dummy code to be used in case the macro errors.
This allows either appending tokens e.g., with ToTokens::to_tokens
or
directly setting the dummy code e.g., *dummy = quote!{some tokens}
.